import { QXEvent } from 'qx-util';
import { ICtrlController } from '@/core/interface/widgets/controller';
import { ICtrlControllerParams } from '@/core/interface/widgets/controller-params';
import {
	CtrlActionType,
	ICtrlEvent,
} from '@/core/interface/widgets/event/i-ctrl-event';
import { ICtrlStore } from '@/core/interface/widgets/store';
import { ControllerBase } from '../common/controller-base';
import { ICtrlAbility, IParam, IViewCtx } from '@/core/interface';
import { LoadingHelper } from '@/core/modules';
import { CtrlMsgContainer } from '@/core/modules/ctrl-msg/ctrl-msg-container';
import { ICtrlModel } from '@/core/interface/widgets/model/i-ctrl-model';

/**
 * 部件控制器
 *
 * @export
 * @class CtrlController
 * @implements {ICtrlController}
 */
export class CtrlController<T, S extends ICtrlStore, A extends ICtrlAbility>
	extends ControllerBase<S, A>
	implements ICtrlController<S, A>
{
	/**
	 * 部件抛出事件
	 *
	 * @protected
	 * @type {Function}
	 * @memberof CtrlController
	 */
	protected evt!: QXEvent<ICtrlEvent<T | CtrlActionType, A>>;

	/**
	 *
	 *
	 * @protected
	 * @type {ICtrlModel}
	 * @memberof CtrlController
	 */
	protected readonly declare model: ICtrlModel;

	/**
	 * 部件消息容器对象
	 *
	 * @type {(CtrlMsgContainer<A> | null)}
	 * @memberof CtrlController
	 */
	 protected CtrlMsgContainer: CtrlMsgContainer | null = null;

	/**
	 * 关闭视图
	 *
	 * @public
	 * @type {(Function | undefined)}
	 * @memberof CtrlController
	 */
	public closeView: Function | undefined;

	/**
	 * Creates an instance of CtrlController.
	 * @param {ICtrlControllerParams} params
	 * @memberof CtrlController
	 */
	constructor(params: ICtrlControllerParams<T, A>) {
		super(params);
		if (
			params.model &&
			params.model.ctrlMsgModel &&
			params.model.ctrlMsgModel.length > 0
		) {
			this.CtrlMsgContainer = new CtrlMsgContainer(
				params.model.ctrlMsgModel
			);
		}
	}

	/**
	 * 部件初始化
	 *
	 * @memberof CtrlController
	 */
	public ctrlInit(params: ICtrlControllerParams<T, A>): void {
		this.beforeCtrlInit(params);
		this.processCtrlInit(params);
		this.afterCtrlInit(params);
	}

	/**
	 * 部件初始化前（准备必要参数）
	 *
	 * @protected
	 * @param {ICtrlControllerParams<T, A>} params
	 * @memberof CtrlController
	 */
	protected beforeCtrlInit(params: ICtrlControllerParams<T, A>) {
		this.evt = params.evt;
		this.closeView = params.closeView;
	}

	/**
	 * 处理部件初始化
	 *
	 * @protected
	 * @param {ICtrlControllerParams<T, A>} params
	 * @memberof CtrlController
	 */
	protected processCtrlInit(params: ICtrlControllerParams<T, A>) {
		this.store = {
			context: {},
			viewParams: {},
			counterData: {},
			loadingHelper: new LoadingHelper('CONTROL', params.pLoadingHelper),
			viewCtx: params.pViewCtx
				? Object.assign(params.pViewCtx as IViewCtx, { ctrl: this })
				: {},
		} as unknown as S;
	}

	/**
	 * 初始化后（对store做处理）
	 *
	 * @protected
	 * @param {ICtrlControllerParams<T, A>} params
	 * @memberof CtrlController
	 */
	protected afterCtrlInit(params: ICtrlControllerParams<T, A>) {
		this.initStore();
		this.evt.emit('ctrlInit', this.name, this.getAbility());
	}

	/**
	 * 部件挂载
	 *
	 * @memberof CtrlController
	 */
	public ctrlMounted(): void {
		this.initCounterData();
		// 处理部件定时器逻辑
		if (this.UIEngineContainer) {
			const inputParam = this.getUIEngineInputParam();
			this.UIEngineContainer.executeTimer(inputParam);
		}
	}

	/**
	 * 部件销毁
	 *
	 * @memberof CtrlController
	 */
	public ctrlDestroy(): void {
		this.destroyCounter();
		if (this.UIEngineContainer) {
			this.UIEngineContainer.destroy();
		}
	}

	/**
	 * 处理子部件初始化
	 *
	 * @param {string} name
	 * @param {ICtrlAbility} ability
	 * @memberof CtrlController
	 */
	public handleCtrlInit(name: string, ability: ICtrlAbility): void {
		this.setSubAbility(name, ability);
	}

	/**
	 * 处理子部件挂载
	 *
	 * @param {string} name
	 * @param {IParam} data
	 * @memberof CtrlController
	 */
	public handleCtrlMounted(name: string, data: IParam): void { }

	/**
	 * 处理子部件行为
	 *
	 * @param {string} name
	 * @param {string} action
	 * @param {IParam[]} data
	 * @memberof CtrlController
	 */
	public handleCtrlAction(name: string, action: string, data: IParam[]): void { }

	/**
	 * 处理子部件销毁
	 *
	 * @param {string} name
	 * @param {IParam} data
	 * @memberof CtrlController
	 */
	public handleCtrlDestroy(name: string, data: IParam): void { }

	/**
	 * 刷新
	 *
	 * @param {(IParam | undefined)} [args]
	 * @return {*}  {Promise<boolean>}
	 * @memberof CtrlController
	 */
	public refresh(args?: IParam | undefined): Promise<boolean> {
		throw new Error('Method not implemented.');
	}

	/**
	 * 获取能力
	 *
	 * @return {*}  {A}
	 * @memberof CtrlController
	 */
	public getAbility(): A {
		return {
			...super.getAbility(),
			refresh: this.refresh.bind(this),
			closeView: this.closeView ? this.closeView.bind(this) : null,
		};
	}

	/**
	 * 抛出事件
	 *
	 * @protected
	 * @template T
	 * @param {string} action
	 * @param {T} data
	 * @memberof CtrlController
	 */
	protected emit(action: T | CtrlActionType, data: IParam[]) {
		this.evt.emit('ctrlAction', this.name, action, data);
	}


	/**
	 * 部件提示
	 *
	 * @param {string} name
	 * @param {*} data
	 * @param {('success' | 'info' | 'warning' | 'error')} type
	 * @param {Function} callback
	 * @memberof CtrlController
	 */
	public alertCtrlNotification(name: string, type: 'success' | 'info' | 'warning' | 'error' = 'success', otherOpt: any = {}) {
		const { controlType } = this.model;
		const data = this.getData();
		const { afterNotification, beforeNotification, showResultInfo } = otherOpt;
		// 内置忽略提示 
		// 但是如果配置了部件消息 还是会提示
		const ignoreAction = [
			'LOADSUCCESS',
			'LOADDRAFTSUCCESS',
		];
		// 消息提示不弹出
		if(otherOpt.hasOwnProperty('showResultInfo') && !showResultInfo){
			return;
		}
		const callback = () => {
			if(ignoreAction.findIndex((item:string)=>{return item === name }) != -1){
				return;
			}
			App.getNotificationHelper()[type](
				App.ts(`app.notificationtitle.${type}`),
				`${beforeNotification || ''}${App.ts(`CONTROL.${controlType}.${name}`)}！${afterNotification || ''}`
			);
		}
		// 部件消息
		if (this.CtrlMsgContainer) {
			const { context, viewParams } = this.store;
			this.CtrlMsgContainer.alertMsg(name, { context, viewParams, data }, type, callback)
		} else {
			callback();
		}
	}
}